#ifndef PTDEF_H__
#define PTDEF_H__

#ifdef __cplusplus
extern "C" {
#endif

#include "stdint.h"
#include "pt_config.h"


#define PT_NULL                         (0)

#define PT_EOK                          0               /**< There is no error */
#define PT_ERROR                        1               /**< A generic error happens */
#define PT_ETIMEOUT                     2               /**< Timed out */
#define PT_EFULL                        3               /**< The resource is full */
#define PT_EEMPTY                       4               /**< The resource is empty */
#define PT_ENOMEM                       5               /**< No memory */
#define PT_ENOSYS                       6               /**< No system */
#define PT_EBUSY                        7               /**< Busy */
#define PT_EIO                          8               /**< IO error */
#define PT_EINTR                        9               /**< Interrupted system call */
#define PT_EINVAL                       10              /**< Invalid argument */
#define PT_PRIVATE                      11

#define PT_ALIGN_SIZE 4
#define PT_ALIGN(size, align)           (((size) + (align) - 1) & ~((align) - 1))
#define PT_ALIGN_DOWN(size, align)      ((size) & ~((align) - 1))

#define PT_WAITING_FOREVER              -1000              /**< Block forever until get resource. */
#define PT_WAITING_NO                   0               /**< Non-block. */

/* Compiler Related Definitions */
#ifdef __CC_ARM                         /* ARM Compiler */
    #define SECTION(x)                  __attribute__((section(x)))
    #define PT_UNUSED                   __attribute__((unused))
    #define PT_USED                     __attribute__((used))
    #define ALIGN(n)                    __attribute__((aligned(n)))
    #define PT_WEAK                     __weak
#elif defined (__GNUC__)                /* GNU GCC Compiler */
    #define SECTION(x)                  __attribute__((section(x)))
    #define PT_UNUSED                   __attribute__((unused))
    #define PT_USED                     __attribute__((used))
    #define ALIGN(n)                    __attribute__((aligned(n)))
    #define PT_WEAK                     __attribute__((weak))
#elif defined (__clang__)                /* CLANG Compiler */
    #define SECTION(x)                  __attribute__((section(x)))
    #define PT_UNUSED                   __attribute__((unused))
    #define PT_USED                     __attribute__((used))
    #define ALIGN(n)                    __attribute__((aligned(n)))
    #define PT_WEAK                     __attribute__((weak))
#else
    #error not supported tool chain
#endif
/**
 * Double List structure
 */
struct pt_list_node
{
    struct pt_list_node *next;                          /**< point to next node. */
    struct pt_list_node *prev;                          /**< point to prev node. */
};
typedef struct pt_list_node pt_list_t;                  /**< Type for lists. */


//根据链表位置找到结构体入口
#define pt_list_entry(ptr, type, member) \
    ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))

 /**
 * @brief initialize a list
 *
 * @param l list to be initialized
 */
static inline void pt_list_init(pt_list_t *l)
{
    l->next = l->prev = l;
}

/**
 * @brief insert a node after a list
 *
 * @param l list to insert it
 * @param n new node to be inserted
 */
static inline void pt_list_insert_after(pt_list_t *l, pt_list_t *n)
{
    l->next->prev = n;
    n->next = l->next;

    l->next = n;
    n->prev = l;
}

/**
 * @brief insert a node before a list
 *
 * @param n new node to be inserted
 * @param l list to insert it
 */
static inline void pt_list_insert_before(pt_list_t *l, pt_list_t *n)
{
    l->prev->next = n;
    n->prev = l->prev;

    l->prev = n;
    n->next = l;
}

/**
 * @brief remove node from list.
 * @param n the node to remove from the list.
 */
static inline void pt_list_remove(pt_list_t *n)
{
    n->next->prev = n->prev;
    n->prev->next = n->next;

    n->next = n->prev = n;
}

/**
 * @brief tests whether a list is empty
 * @param l the list to test.
 */
static inline int pt_list_isempty(const pt_list_t *l)
{
    return l->next == l;
}
/**
 * @brief tests whether a list is initialized
 * @param l the list to test. 1 on initialized, otherwise 0
 */
static inline int pt_list_isinit(const pt_list_t *l)
{
    if(l->next != PT_NULL && l->prev != PT_NULL){
        return 1;
    }else{
        return 0;
    }
}
static inline void pt_hw_interrupt_enable(void)
{
#if !defined (_WIN32) && defined (__CC_ARM) && defined (PT_USING_INT_ONOFF)
    __enable_irq();
#endif
}

static inline void pt_hw_interrupt_disable(void)
{
#if !defined (_WIN32) && defined (__CC_ARM) && defined (PT_USING_INT_ONOFF)
    __disable_irq();
#endif
}


/**
 * device flags defitions
 */
#define PT_DEVICE_FLAG_DEACTIVATE       0x000           /**< device is not not initialized */

#define PT_DEVICE_FLAG_RDONLY           0x001           /**< read only */
#define PT_DEVICE_FLAG_WRONLY           0x002           /**< write only */
#define PT_DEVICE_FLAG_RDWR             0x003           /**< read and write */

#define PT_DEVICE_FLAG_REMOVABLE        0x004           /**< removable device */
#define PT_DEVICE_FLAG_STANDALONE       0x008           /**< standalone device */
#define PT_DEVICE_FLAG_ACTIVATED        0x010           /**< device is activated */
#define PT_DEVICE_FLAG_SUSPENDED        0x020           /**< device is suspended */
#define PT_DEVICE_FLAG_STREAM           0x040           /**< stream mode */

#define PT_DEVICE_FLAG_INT_RX           0x100           /**< INT mode on Rx */
#define PT_DEVICE_FLAG_DMA_RX           0x200           /**< DMA mode on Rx */
#define PT_DEVICE_FLAG_INT_TX           0x400           /**< INT mode on Tx */
#define PT_DEVICE_FLAG_DMA_TX           0x800           /**< DMA mode on Tx */

#define PT_DEVICE_OFLAG_CLOSE           0x000           /**< device is closed */
#define PT_DEVICE_OFLAG_RDONLY          0x001           /**< read only access */
#define PT_DEVICE_OFLAG_WRONLY          0x002           /**< write only access */
#define PT_DEVICE_OFLAG_RDWR            0x003           /**< read and write */
#define PT_DEVICE_OFLAG_OPEN            0x008           /**< device is opened */
#define PT_DEVICE_OFLAG_MASK            0xf0f           /**< mask of open flag */

/**
 * general device commands
 */
#define PT_DEVICE_CTRL_RESUME           0x01            /**< resume device */
#define PT_DEVICE_CTRL_SUSPEND          0x02            /**< suspend device */
#define PT_DEVICE_CTRL_CONFIG           0x03            /**< configure device */

#define PT_DEVICE_CTRL_SET_INT          0x10            /**< set interrupt */
#define PT_DEVICE_CTRL_CLR_INT          0x11            /**< clear interrupt */
#define PT_DEVICE_CTRL_GET_INT          0x12            /**< get interrupt status */

/**
 * special device commands
 */
#define PT_DEVICE_CTRL_CHAR_STREAM      0x10            /**< stream mode on char device */
#define PT_DEVICE_CTRL_BLK_GETGEOME     0x10            /**< get geometry information   */
#define PT_DEVICE_CTRL_BLK_SYNC         0x11            /**< flush data to block device */
#define PT_DEVICE_CTRL_BLK_ERASE        0x12            /**< erase block on block device */
#define PT_DEVICE_CTRL_BLK_AUTOREFRESH  0x13            /**< block device : enter/exit auto refresh mode */
#define PT_DEVICE_CTRL_NETIF_GETMAC     0x10            /**< get mac address */
#define PT_DEVICE_CTRL_MTD_FORMAT       0x10            /**< format a MTD device */
#define PT_DEVICE_CTRL_RTC_GET_TIME     0x10            /**< get time */
#define PT_DEVICE_CTRL_RTC_SET_TIME     0x11            /**< set time */
#define PT_DEVICE_CTRL_RTC_GET_ALARM    0x12            /**< get alarm */
#define PT_DEVICE_CTRL_RTC_SET_ALARM    0x13            /**< set alarm */


/**
 * device (I/O) class type
 */
enum pt_device_class_type
{
    PT_Device_Class_Char = 0,                           /**< character device */
    PT_Device_Class_Block,                              /**< block device */
    PT_Device_Class_NetIf,                              /**< net interface */
    PT_Device_Class_MTD,                                /**< memory device */
    PT_Device_Class_CAN,                                /**< CAN device */
    PT_Device_Class_RTC,                                /**< RTC device */
    PT_Device_Class_Sound,                              /**< Sound device */
    PT_Device_Class_Graphic,                            /**< Graphic device */
    PT_Device_Class_I2CBUS,                             /**< I2C bus device */
    PT_Device_Class_USBDevice,                          /**< USB slave device */
    PT_Device_Class_USBHost,                            /**< USB host bus */
    PT_Device_Class_SPIBUS,                             /**< SPI bus device */
    PT_Device_Class_SPIDevice,                          /**< SPI device */
    PT_Device_Class_SDIO,                               /**< SDIO bus device */
    PT_Device_Class_PM,                                 /**< PM pseudo device */
    PT_Device_Class_Pipe,                               /**< Pipe device */
    PT_Device_Class_Portal,                             /**< Portal device */
    PT_Device_Class_Timer,                              /**< Timer device */
    PT_Device_Class_Miscellaneous,                      /**< Miscellaneous device */
    PT_Device_Class_Unknown                             /**< unknown device */
};


enum pt_object_class_type
{
    PT_Object_Class_Thread = 0,                         /**< The object is a thread. */
    PT_Object_Class_Semaphore,                          /**< The object is a semaphore. */
    PT_Object_Class_Mutex,                              /**< The object is a mutex. */
    PT_Object_Class_Event,                              /**< The object is a event. */
    PT_Object_Class_MailBox,                            /**< The object is a mail box. */
    PT_Object_Class_MessageQueue,                       /**< The object is a message queue. */
    PT_Object_Class_MemHeap,                            /**< The object is a memory heap */
    PT_Object_Class_MemPool,                            /**< The object is a memory pool. */
    PT_Object_Class_Device,                             /**< The object is a device */
    PT_Object_Class_Timer,                              /**< The object is a timer. */
    PT_Object_Class_Module,                             /**< The object is a module. */
    PT_Object_Class_Unknown,                            /**< The object is unknown. */
    PT_Object_Class_Static = 0x80                       /**< The object is a static object. */
};
typedef struct pt_device *pt_device_t;
/**
 * Device structure
 */
struct pt_device
{

    enum pt_device_class_type type;                     /**< device type */
    uint16_t                flag;                     /**< device flag */
    uint16_t                open_flag;                /**< device open flag */

    uint8_t                 ref_count;                /**< reference count */
    uint8_t                 device_id;                /**< 0 - 255 */

    pt_list_t               d_list;

    /* device call back */
    int32_t (*rx_indicate)(pt_device_t dev, uint32_t size);
    int32_t (*tx_complete)(pt_device_t dev, void *buffer);

    /* common device interface */
    int32_t  (*init)   (pt_device_t dev);
    int32_t  (*open)   (pt_device_t dev, uint16_t oflag);
    int32_t  (*close)  (pt_device_t dev);
    uint32_t (*read)   (pt_device_t dev, int32_t pos, void *buffer, uint32_t size);
    uint32_t (*write)  (pt_device_t dev, int32_t pos, const void *buffer, uint32_t size);
    int32_t  (*control)(pt_device_t dev, int cmd, void *args);

    void                     *user_data;                /**< device private data */
};

/**
 * operations set for device object
 */
struct pt_device_ops
{
    /* common device interface */
    int32_t  (*init)   (pt_device_t dev);
    int32_t  (*open)   (pt_device_t dev, uint16_t oflag);
    int32_t  (*close)  (pt_device_t dev);
    uint32_t (*read)   (pt_device_t dev, int32_t pos, void *buffer, uint32_t size);
    uint32_t (*write)  (pt_device_t dev, int32_t pos, const void *buffer, uint32_t size);
    int32_t  (*control)(pt_device_t dev, int cmd, void *args);
};

struct timer {
    uint32_t    start;
    uint32_t    interval;
    uint8_t     flag;                                   //定时器模式
    void        *parameter;                             //超时函数的参数
    void        (*timeout_func)(void *parameter);       //定时器超时回调函数
    pt_list_t   t_list;                                 //定时器链表, 用于检查定时器超时

};

#define PT_THREAD(name_args) char name_args
#include "lc.h"
struct pt {
	lc_t lc;
	unsigned char alive;                            //协程存活标志
	unsigned char suspend_state;                    //协程挂起标志
    PT_THREAD(  (*entry)(struct pt *pt) );          //协程入口函数
    pt_list_t tlist;                                //协程链表节点

    uint16_t    thread_id;                          //协程id

#ifdef PT_USING_THREAD_MB
    struct pt_mailbox *mb_thread;                   //内部邮箱
#endif

#if defined(PT_USING_EVENT)
    /* thread event */
    uint32_t event_set;
    uint8_t  event_info;
#endif

    struct timer thread_timer;                      //内部定时器

};
#define PT_PROCESS_SUSPEND      0
#define PT_PROCESS_RESUME       (!PT_PROCESS_SUSPEND)
#define PT_PROCESS_DEAD         0
#define PT_PROCESS_ALIVE        (!PT_PROCESS_DEAD)

#define PT_WAITING      0
#define PT_YIELDED      1
#define PT_EXITED       2
#define PT_ENDED        3
#define PT_KILLED       4

/**
 * sem structure
 */

struct pt_sem {
    pt_list_t           suspend_thread;   /**< threads pended on this resource */
    unsigned int        count;
};

/**
 * mailbox structure
 */
struct pt_mailbox
{
    uint32_t            *msg_pool;                      /**< start address of message buffer */

    uint16_t            size;                          /**< size of message pool */

    uint16_t            entry;                         /**< index of messages in msg_pool */
    uint16_t            in_offset;                     /**< input offset of the message buffer */
    uint16_t            out_offset;                    /**< output offset of the message buffer */
//    struct pt           *suspend_rcv_thread;         /**< sender thread suspended on this mailbox */
    pt_list_t            suspend_sender_thread;         /**< sender thread suspended on this mailbox */
    pt_list_t            suspend_reciever_thread;         /**< sender thread suspended on this mailbox */
};
typedef struct pt_mailbox *pt_mailbox_t;

struct pt_messagequeue
{
    void                *msg_pool;                      /**< stapt address of message queue */

    uint16_t            msg_size;                      /**< message size of each message */
    uint16_t            max_msgs;                      /**< max number of messages */

    uint16_t            entry;                         /**< index of messages in the queue */

    void                *msg_queue_head;               /**< list head */
    void                *msg_queue_tail;               /**< list tail */
    void                *msg_queue_free;               /**< pointer indicated the free node of queue */

    pt_list_t           suspend_sender_thread;         /**< sender thread suspended on this msgq */
    pt_list_t           suspend_reciever_thread;       /**< reciever thread suspended on this msgq */
};
typedef struct pt_messagequeue *pt_mq_t;


#ifdef PT_USING_MUTEX
#define MUTEX_STATUS_LOCKED   1 /** The mutex is locked */
#define MUTEX_STATUS_UNLOCKED 0 /** The mutex is not locked */
/**
 * Mutual exclusion (mutex) structure
 */
struct pt_mutex
{
    uint16_t          value;                         /**< value of mutex */
    pt_list_t         suspend_taker_thread;         /**< taker thread suspended on this msgq */
    pt_list_t         suspend_releaser_thread;       /**< releaser thread suspended on this msgq */
};
typedef struct pt_mutex *pt_mutex_t;

#endif // PT_USING_MUTEX

#ifdef PT_USING_EVENT
/**
 * flag defintions in event
 */
#define PT_EVENT_FLAG_AND               0x01            /**< logic and */
#define PT_EVENT_FLAG_OR                0x02            /**< logic or */
#define PT_EVENT_FLAG_CLEAR             0x04            /**< clear flag */
#define PT_EVENT_FLAG_RCVED_OR          0x08            /**< rcved or flag */
#define PT_EVENT_FLAG_RCVED_AND         0x10            /**< rcved or flag */

#define PT_EVENT_CMD_RESET              0x01
/*
 * event structure
 */
struct pt_event
{
    uint32_t        set;                           /**< event set */
    pt_list_t       suspend_thread;                /**< threads pended on this resource */
};
typedef struct pt_event *pt_event_t;

#endif // PT_USING_EVENT



#ifdef __cplusplus
}
#endif

#endif // PTDEF_H__
